被翻译的文章
<nginx url rewriting:difference between break and last>此提问的第二回答,即有例子的那一篇。
前置条件
安装 echo-nginx-module 模块到 nginx 上,安装方法可见我的这篇文章:为已经安装好的nginx动态添加新模块echo-nginx-module。
阅读本文者应当对如何修改 nginx 的配置文件以及如何重启 nginx 使其应用新的配置文件有所了解,并且对 server 和 location 这两个基本的模块有所了解。
相关资料
If the specified regular expression matches a request URI, URI is changed as specified in the replacement string. The rewrite directives are executed sequentially in order of their appearance in the configuration file. It is possible to terminate further processing of the directives using flags. If a replacement string starts with “http://”, “https://”, or “$scheme”, the processing stops and the redirect is returned to a client.
last
stops processing the current set ofngx_http_rewrite_module
directives and starts a search for a new location matching the changed URI;
break
stops processing the current set ofngx_http_rewrite_module
directives as with the breakdirective;
开始
Example 1: No (break or last) flags
code
server {
server_name example.com;
root 'path/to/somewhere';
location / {
echo 'finally matched location /';
}
location /notes {
echo 'finally matched location /notes';
}
location /documents {
echo 'finally matched location /documents';
}
rewrite ^/(.*\.txt)$ /notes/$1;
rewrite ^/notes/(.*\.txt)$ /documents/$1;
}
Result:
# curl example.com/test.txt
finally matched location /documents
Explanation:
For rewrite
, the flags are optional!
翻译和解读
第一个例子里break
和last
一个不用,考察在这种情况下程序能否正常运行。
从结果来看,输入的/test.txt
被最终被rewrite为了/documents/test.txt
,其内部的过程其实是/test.txt
->/notes/test.txt
->/documents/test.txt
,与官方文档中说的
The rewrite directives are executed sequentially in order of their appearance in the configuration file.
rewrite指令会按写下的顺序执行相符合。证明了break
和last
参数可以没有。
Example 2: Outside location block (break or last)
code
server {
server_name example.com;
root 'path/to/somewhere';
location / {
echo 'finally matched location /';
}
location /notes {
echo 'finally matched location /notes';
}
location /documents {
echo 'finally matched location /documents';
}
rewrite ^/(.*\.txt)$ /notes/$1 break; # or last
rewrite ^/notes/(.*\.txt)$ /documents/$1; # this is not parsed
}
Result:
# curl example.com/test.txt
finally matched location /notes
Explanation:
Outside the location block, both break
and last
behave in the exact manner...
- no more parsing of rewrite conditions
- Nginx internal engine goes to the next phase (searching for
location
match)
翻译和解读
此处测试了当rewrite
指令在server
块内,但在location
块外的情景下,break
或last
参数带来的影响。官方文档对此没有做特别说明,原文作者的测试时发现,使用break
或last
造成的最终效果一样。都是阻止了第二条rewrite
指令的发生,然后进入下一个阶段——在rewrite
指令改写的结果的基础上搜寻对应的location
块。
Example 3: Inside location block - "break"
code
server {
server_name example.com;
root 'path/to/somewhere';
location / {
rewrite ^/(.*\.txt)$ /notes/$1 break;
rewrite ^/notes/(.*\.txt)$ /documents/$1; # this is not parsed
echo 'finally matched location /';
}
location /notes {
echo 'finally matched location /notes';
}
location /documents {
echo 'finally matched location /documents';
}
}
Result:
# curl example.com/test.txt
finally matched location /
Explanation:
Inside a location block,break
flag would do the following...
- no more parsing of rewrite conditions
- Nginx internal engine continues to parse the current
location
block
翻译和解读
前面的逻辑是很简单的:/test.txt
在进入后,因为server
块中没有rewrite
指令,开始location
块匹配,进入location /
块,会被rewrite ^/(.*\.txt)$ /notes/$1 break;
抓住。
然后发生了什么呢?结合输出结果。输出的结果为finally matched location /
。这说明被抓住之后,值被改了,但是仍然在继续执行当前location
块内的事情,并不会拿着被改掉之后的值,重新进入寻找适配location
块的阶段。
另外,这里没有再单独测试什么参数都不带的情况。我自己测试之后的话最终输出会是finally matched location /documents
。说明正常情况下和在外部并没有区别。
Example 4: Inside location block - "last"
code
server {
server_name example.com;
root 'path/to/somewhere';
location / {
echo 'finally matched location /';
rewrite ^/(.*\.txt)$ /notes/$1 last;
rewrite ^/notes/([^/]+.txt)$ /documents/$1; # this is not parsed
}
location /notes {
echo 'finally matched location /notes';
rewrite ^/notes/(.*\.txt)$ /documents/$1; # this is not parsed, either!
}
location /documents {
echo 'finally matched location /documents';
}
}
Result:
# curl example.com/test.txt
finally matched location /notes
Explanation:
Inside a location block,last
flag would do the following...
- no more parsing of rewrite conditions
- Nginx internal engine starts to look for another location match based on the result of the
rewrite
result. - no more parsing of rewrite conditions, even on the next location match!
翻译和解读
前面被抓住的推理部分一模一样。
被抓住然后做了些什么?这次输出结果不一样了,变成了finally matched location /notes
,说明抓住之后被改了之后,又以被改变之后的值,再次进入寻找合适的location
块的阶段。所以跑到了location /notes
那儿去,造成了那里的echo。
在此基础上有另一件事情,那就是在此进入寻找合适的location
块的阶段中,会不会被外部的rewrite
指令处理到呢?
比如
server {
server_name example.com;
root 'path/to/somewhere';
location / {
echo 'finally matched location /';
rewrite ^/(.*\.txt)$ /notes/$1 last;
rewrite ^/notes/([^/]+.txt)$ /documents/$1; # this is not parsed
}
location /notes {
echo 'finally matched location /notes';
rewrite ^/notes/(.*\.txt)$ /documents/$1; # this is not parsed, either!
}
location /documents {
echo 'finally matched location /documents';
}
rewrite ^/notes/(.*\.txt)$ /documents/$1; //新增的外部的rewrite指令
}
我这里经过测试,答案是不会。
Summary:
原文
- When a
rewrite
condition with the flagbreak
orlast
matches, Nginx stops parsing any morerewrites
! - Outside a location block, with
break
orlast
, Nginx does the same job (stops processing anymore rewrite conditions). - Inside a location block, with
break
, Nginx only stops processing anymore rewrite conditions - Inside a location block, with
last
, Nginx stops processing anymore rewrite conditions and then starts to look for a new matching oflocation
block! Nginx also ignores anyrewrites
in the newlocation
block!
翻译
-
break
和last
参数放在rewrite
指令后,无论如何一定会产生使这条rewrite
指令之后的rewrite
指令无效的效果。 - 在
location
块外使用break
或last
,对rewrite
指令造成的效果一样,除了第一条的打断效果外,都会让rewrite
指令的结果进入搜寻适配的location
块的阶段。 - 在
location
块内使用break
,打断rewrite
指令流后,继续执行当前location
块中的其它(模块的)任务。 - 在
location
块内使用last
,打断rewrite
指令流后,会以rewrite
指令的结果为新被适配者去搜寻自己合适的location
块并进入,rewrite
指令所在的location
块内其它(模块的)任务被放弃。但不会受外部rewrite
指令的影响。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。